﻿/*========================== 
 * @author 郑金泉
 * @desc 会话类，用于存取登录会话信息
 *       支持MemCached和数据库
 * @created 2014-11-20
 * ========================= */
using System;
using System.Collections.Generic;
using System.Text;

using Obsidian.Action;
using Obsidian.Edm;
using Obsidian.Utils;
using Obsidian.Data;
using Oak.Config;
using Oak.Model;
using Oak.Core.Data;

namespace Oak.Core
{
    public abstract class Session : IOSession
    {
        private const string MC_SK_PREFIX = "_SESSION_KEY_";
        private string sessionKey;

        public Session(string sessionKey)
        {
            this.sessionKey = sessionKey;
        }

        public string SessionKey
        {
            get { return this.sessionKey; }
        }

        /// <summary>
        /// 设置会话实体信息，返回SessionKey
        /// </summary>
        public static string Set(IModel model)
        {
            string sessionKey = Guid.NewGuid().ToString().Replace("-", "").ToLower();

            SessionConfig.SessionInfo sessConf = SessionConfig.GetSessionInfo();
            if (sessConf.Type == SessionConfig.SessionType.DataBase)
                InsertDbSession(sessionKey, model, sessConf.ValidTime);
            else if (sessConf.Type == SessionConfig.SessionType.Memcached)
                SetToMemCached(sessionKey, model, sessConf.ValidTime);

            return sessionKey;
        }

        /// <summary>
        /// 获得会话实体信息
        /// </summary>
        /// <returns></returns>
        public static T Get<T>(string sessionKey) where T : IModel, new()
        {
            SessionConfig.SessionInfo sessConf = SessionConfig.GetSessionInfo();
            if (sessConf.Type == SessionConfig.SessionType.DataBase)
            {
                CoSessionInfo session = SelectDbSessionBySessionKey(sessionKey);
                if (session == null)
                    return default(T);
                T o = ModelUtil.ToModel<T>(session.Data.Value);
                return o;
            }
            else if (sessConf.Type == SessionConfig.SessionType.Memcached)
            {
                string strJson = GetFromMemCached(sessionKey);
                if (String.IsNullOrEmpty(strJson))
                    return default(T);
                T o = ModelUtil.ToModel<T>(strJson);
                SetToMemCached(sessionKey, o, sessConf.ValidTime);
                return o;
            }
            else
            {
                throw new Exception("SessionType未设置");
            }
        }

        /// <summary>
        /// 移除会话信息
        /// </summary>
        /// <param name="sessionKey"></param>
        /// <returns></returns>
        public static bool Remove(string sessionKey)
        {
            SessionConfig.SessionInfo sessConf = SessionConfig.GetSessionInfo();
            if (sessConf.Type == SessionConfig.SessionType.DataBase)
            {
                return DeleteDbSession(sessionKey);
            }
            else if (sessConf.Type == SessionConfig.SessionType.Memcached)
            {
                return RemoveFromMemCached(sessionKey);
            }
            else
            {
                throw new Exception("SessionType未设置");
            }

        }


        /// <summary>
        /// 将会话信息存到MemCached
        /// </summary>
        /// <param name="sessionKey"></param>
        /// <param name="model">实体信息</param>
        /// <param name="validTime">有效时间</param>
        private static void SetToMemCached(string sessionKey, IModel model, int validTime)
        {
            sessionKey = MC_SK_PREFIX + sessionKey;
            if (validTime <= 0)
                validTime = 20;
            validTime = validTime * 60;
            string strJson = ModelUtil.ToJsonString(model);
            MemCached.Set(sessionKey, strJson, validTime);
        }

        /// <summary>
        /// 从MemCached获得会话信息
        /// </summary>
        /// <param name="sessionKey"></param>
        /// <returns></returns>
        private static string GetFromMemCached(string sessionKey)
        {
            sessionKey = MC_SK_PREFIX + sessionKey;
            return MemCached.Get(sessionKey);
        }

        /// <summary>
        /// 从MemCached移除会话信息
        /// </summary>
        /// <param name="sessionKey"></param>
        /// <returns></returns>
        private static bool RemoveFromMemCached(string sessionKey)
        {
            sessionKey = MC_SK_PREFIX + sessionKey;
            return MemCached.Delete(sessionKey);
        }

        /// <summary>
        /// 将会话信息存到数据库
        /// </summary>
        /// <param name="sessionKey"></param>
        /// <param name="model">实体信息</param>
        /// <param name="validTime">有效时间</param>
        /// <returns></returns>
        private static CoSessionInfo InsertDbSession(string sessionKey, IModel model, int validTime)
        {
            CoSessionInfo s = OModel.GetByPk<CoSessionInfo>(sessionKey);

            if (s != null)
                throw new Exception(String.Format("SessionKey：{0} 已存在", sessionKey));

            string strJson = ModelUtil.ToJsonString(model);
            DateTime dtNow = DateTime.Now;
            s = new CoSessionInfo();
            s.SessionKey.Set(sessionKey);
            s.LoginTime.Set(dtNow);
            s.Data.Set(strJson);
            s.Expires.Set(validTime);
            s.AccessTime.Set(dtNow);
            s.ExpiresTime.Set(dtNow.AddMinutes(validTime));
            s.Save();

            return s;
        }

        /// <summary>
        /// 从数据库获得会话信息
        /// </summary>
        /// <param name="sessionKey"></param>
        /// <returns></returns>
        private static CoSessionInfo SelectDbSessionBySessionKey(string sessionKey)
        {
            SessionDA sessionDA = new SessionDA();
            CoSessionInfo session = sessionDA.SelectSessionByKey(sessionKey, DateTime.Now);
            return session;
        }

        /// <summary>
        /// 从数据库移除会话信息
        /// </summary>
        /// <param name="sessionKey"></param>
        /// <returns></returns>
        private static bool DeleteDbSession(string sessionKey)
        {
            SessionDA sessionDA = new SessionDA();
            int n = sessionDA.DeleteSessionByKey(sessionKey);
            return n == 1;
        }

    }
}
